﻿using System;
using System.Drawing;
using System.Linq.Expressions;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;

namespace IL_Dynamically_Assembly
{
    class Program
    {
        static void Main(string[] args)
        {
            GetMethodAddress(() => Method1(), () => Method2());

            Method1();


        }





        static void Method1()
        {
            Console.WriteLine("Program.Method1");
        }

        static void Method2()
        {
            Console.WriteLine("Program.Method2");
        }

        static void GetMethodAddress(Expression<Action> srcMethodExpr, Expression<Action> destMethodExpr)
        {
            var srcMethod = ((MethodCallExpression)srcMethodExpr.Body).Method;
            var destMethod = ((MethodCallExpression)destMethodExpr.Body).Method;

            Console.WriteLine("MethodAddress: {0},{1}", srcMethod.MethodHandle.GetFunctionPointer().ToInt64(),
                destMethod.MethodHandle.GetFunctionPointer().ToInt64());

            RuntimeHelpers.PrepareMethod(srcMethod.MethodHandle);
            RuntimeHelpers.PrepareMethod(destMethod.MethodHandle);

            Console.WriteLine("MethodAddress: {0},{1}", srcMethod.MethodHandle.GetFunctionPointer().ToInt64(),
                destMethod.MethodHandle.GetFunctionPointer().ToInt64());




            var sourceAddress = srcMethod.MethodHandle.GetFunctionPointer();
            var targetAddress = (long)destMethod.MethodHandle.GetFunctionPointer();

            //unsafe
            //{
            //    int* point = (int*)srcMethod.MethodHandle.Value.ToPointer() + 2;
            //    int* destPoint = (int*)destMethod.MethodHandle.Value.ToPointer() + 2;
            //    *point = *destPoint;
            //}

            int offset = (int)(targetAddress - (long)sourceAddress - 4 - 1);



            byte[] instruction = {
                0xE9, // JUMP
                (byte)(offset & 0xFF),
                (byte)((offset >> 8) & 0xFF),
                //(byte)((offset >> 16) & 0xFF),
                //(byte)((offset >> 24) & 0xFF)
            };

            Marshal.Copy(instruction, 0, sourceAddress, instruction.Length);
        }
    }
}
